package com.wtf.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.*;
import java.util.stream.Collectors;

/**
 * desc:
 *
 * @author tengfei wang
 * @version 1.0
 * @date Created in 3/11/2020
 */
@Component
@Slf4j
public class BlackListFilter implements GlobalFilter, Ordered {

    private static final Map<String, LinkedList<Long>> IP_MAP = new HashMap<>();

    private static final String REGISTER_URL = "/user/register";

    @Value("${max.request.size}")
    private Integer maxRequestSize;

    @Value("${max.request.time}")
    private Integer maxRequestTime;


    /**
     * @param exchange 封装了request和response对象上下文
     * @param chain    网管过滤器链
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String uriPath = request.getURI().getPath();
        String hostIp = Objects.requireNonNull(request.getRemoteAddress()).getHostString();

        if (isAddBlackList(uriPath, hostIp)) {
            log.error("ip {} 频繁注册，已被拒绝", hostIp);
            response.setStatusCode(HttpStatus.OK);
            response.getHeaders().set("Content-Type", "text/plain; charset=UTF-8");

            DataBuffer wrap = response.bufferFactory().wrap("频繁注册，已被拒绝".getBytes());
            return response.writeWith(Mono.just(wrap));
        }

        return chain.filter(exchange);
    }

    private boolean isAddBlackList(String uriPath, String hostIp) {
        if (uriPath.contains(REGISTER_URL)) {
            LinkedList<Long> list = IP_MAP.get(hostIp);
            // 请求次数小于0直接返回false
            if (list == null || list.size() <= 0) {
                LinkedList<Long> longs = new LinkedList<>();
                longs.add(System.currentTimeMillis());
                IP_MAP.put(hostIp, longs);
                return false;
            }
            // 请求次数小于最大请求次数，直接返回false
            if (list.size() < maxRequestSize) {
                LinkedList<Long> longs = IP_MAP.get(hostIp);
                longs.add(System.currentTimeMillis());
                IP_MAP.put(hostIp, longs);
                return false;
            }

            long currentTime = System.currentTimeMillis();
            currentTime = currentTime - maxRequestTime * 60 * 1000;
            final Long time = currentTime;
            List<Long> collect = list.stream().filter(w -> w > time).collect(Collectors.toList());
            // 在设定时间内的请求次数小于最大请求次数，直接返回false
            if (collect.size() < maxRequestSize) {
                LinkedList<Long> longs = IP_MAP.get(hostIp);
                longs.add(System.currentTimeMillis());
                IP_MAP.put(hostIp, longs);
                return false;
            } else {
                return true;
            }
        }
        return false;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
